package br.senai.sc.controller.business;

import java.io.Serializable;
import java.math.BigInteger;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.jboss.seam.international.status.Messages;
import org.jboss.seam.international.status.builder.BundleKey;

import br.senai.sc.model.Amostra;
import br.senai.sc.util.SystemConstants;

/**
 * Contém as regras de negócios relacionadas a entidade {@link Amostra}.
 * 
 * @author Tiago Wanke Marques &lt;tiago.marques@sc.senai.br&gt;
 */
public class AmostraBusiness implements Serializable {

	private static final long serialVersionUID = 1L;

	@PersistenceContext
	private EntityManager em;

	@Inject
	private Messages messages;

	@Inject
	private PontoColetaBusiness pontoColetaBusiness;

	@Inject
	private CondicaoClimaticaBusiness condicaoClimaticaBusiness;

	/**
	 * @param amostra
	 * @return True caso a {@link Amostra} exista, false caso contrário.
	 */
	public boolean existe(Amostra amostra) {

		if ((amostra == null) || (amostra.getIdAmostra() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM amostra a WHERE id_amostra = :idAmostra")
				.setParameter("idAmostra", amostra.getIdAmostra())
				.getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * @param amostra
	 * @return True caso exista uma {@link Amostra} com mesma data e no mesmo
	 *         {@link br.senai.sc.model.PontoColeta} do informado.
	 */
	public boolean mesmaDataEPontoColeta(Amostra amostra) {

		if ((amostra == null) || (amostra.getData() == null)
				|| (amostra.getPontoColeta() == null)
				|| (amostra.getPontoColeta().getIdPontoColeta() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM amostra a WHERE data = :data AND id_ponto_coleta = :idPontoColeta")
				.setParameter("data", amostra.getData())
				.setParameter("idPontoColeta",
						amostra.getPontoColeta().getIdPontoColeta())
				.getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * @param amostra
	 * @return True caso exista uma {@link Amostra} com mesma data e no mesmo
	 *         {@link br.senai.sc.model.PontoColeta} do informado, porém com id
	 *         diferente.
	 */
	public boolean mesmaDataEPontoColetaIdDiferente(Amostra amostra) {

		if ((amostra == null) || (amostra.getIdAmostra() == null)
				|| (amostra.getData() == null)
				|| (amostra.getPontoColeta() == null)
				|| (amostra.getPontoColeta().getIdPontoColeta() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM amostra a WHERE data = :data AND id_ponto_coleta = :idPontoColeta AND id_amostra != :idAmostra")
				.setParameter("idAmostra", amostra.getIdAmostra())
				.setParameter("data", amostra.getData())
				.setParameter("idPontoColeta",
						amostra.getPontoColeta().getIdPontoColeta())
				.getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * Executa os métodos necessários para verificar se a {@link Amostra} pode
	 * ser salva. Caso houver alguma inconsistência adiciona ao atributo de
	 * mensagens da classe.
	 * 
	 * @param amostra
	 * @return True caso a {@link Amostra} pode ser salva, false caso contrário.
	 */
	public boolean podeSalvar(Amostra amostra) {

		messages.clear();

		if (mesmaDataEPontoColeta(amostra)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"amostras.validacao.mesmaDataMesmoPonto"));
		}

		if (!pontoColetaBusiness.existe(amostra.getPontoColeta())) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"pontosColeta.validacao.pontoColetaInexistente"));
		}

		if (!condicaoClimaticaBusiness.condicaoClimaticaExiste(amostra
				.getCondicaoClimatica())) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"amostras.validacao.condicaoClimaticaInexistente"));
		}

		return messages.isEmpty();
	}

	/**
	 * Executa os métodos necessários para verificar se a {@link Amostra} pode
	 * ser editada. Caso houver alguma inconsistência adiciona ao atributo de
	 * mensagens da classe.
	 * 
	 * @param amostra
	 * @return True caso a {@link Amostra} pode ser editada, false caso
	 *         contrário.
	 */
	public boolean podeEditar(Amostra amostra) {

		messages.clear();

		if (!existe(amostra)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"amostras.validacao.amostraAnexistente"));
			return false;
		}

		if (mesmaDataEPontoColetaIdDiferente(amostra)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"amostras.validacao.mesmaDataMesmoPonto"));
		}

		if (!pontoColetaBusiness.existe(amostra.getPontoColeta())) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"pontosColeta.validacao.pontoColetaInexistente"));
		}

		if (!condicaoClimaticaBusiness.condicaoClimaticaExiste(amostra
				.getCondicaoClimatica())) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"amostras.validacao.condicaoClimaticaInexistente"));
		}
		return messages.isEmpty();
	}

	/**
	 * Executa os métodos necessários para verificar se a {@link Amostra} pode
	 * ser removida. Caso houver alguma inconsistência adiciona ao atributo de
	 * mensagens da classe.
	 * 
	 * @param amostra
	 * @return True caso a {@link Amostra} pode ser removida, false caso
	 *         contrário.
	 */
	public boolean podeRemover(Amostra amostra) {

		messages.clear();

		if (!existe(amostra)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"bacias.inexistente"));
		}

		return messages.isEmpty();
	}

}
